/* Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * This file is a part of the CANN Open Software.
 * Licensed under CANN Open Software License Agreement Version 1.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 * ===================================================================================================================*/


#include "inc/graph/ascend_ir/ascend_ir.h"
#include "ascend_ir_impl.h"
#include "graph/utils/graph_utils.h"
#include "graph/utils/graph_utils_ex.h"
#include "graph/utils/op_desc_utils.h"
#include "graph/utils/node_utils_ex.h"
#include "graph/utils/cg_utils.h"
#include "graph/debug/ge_log.h"
#include "graph/debug/ge_op_types.h"

#define CHECK_FALSE_RETURN_FALSE(expr, err_log, ...) \
  if (!(expr)) { \
    GE_LOGE(err_log, ##__VA_ARGS__); \
    return false; \
  }
namespace ge {
namespace {
constexpr int32_t kDefaultAlignVal = 8;
constexpr uint32_t kMinMergeAxisFromSize = 2U;
const std::vector<std::vector<int64_t>> kOneAxisContinuousInfo = {{0, -1}};
const char *const kAscData = ge::DATA;
const char *const kAscOutput = "Output";
}
AscIRException::AscIRException(const AscIRException::Info &info) : std::exception(), info_(info) {}

const AscIRException::Info &AscIRException::GetInfo() const {
  return info_;
}

AttrGroupsBase *AscGraphAttr::CreateNew() {
  return new (std::nothrow) AscGraphAttr(*this);
}

AscNodeAttr &AscNodeAttr::GetAttrGroup(ge::Operator& op) {
  auto opdesc = ge::OpDescUtils::GetOpDescFromOperator(op).get();
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(opdesc);
  auto attr_group = opdesc->GetOrCreateAttrsGroup<AscNodeAttr>();
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(attr_group);
  return *attr_group;
}

AttrGroupsBase *AscNodeAttr::CreateNew() {
  return new (std::nothrow) AscNodeAttr(*this);
}

AscTensorAttr &AscTensorAttr::GetTensorAttr(ge::Operator *op, const uint32_t index) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(op);
  const auto desc = ge::OpDescUtils::GetOpDescFromOperator(*op);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(desc->MutableOutputDesc(index));
  const auto attr_group = desc->MutableOutputDesc(index)->GetOrCreateAttrsGroup<AscTensorAttr>();
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(attr_group);
  return *attr_group;
}

AttrGroupsBase *AscTensorAttr::CreateNew() {
  return new (std::nothrow) AscTensorAttr(*this);
}

AscNodeOutputs::AscNodeOutputs(const ge::OpDescPtr &op_desc) : op_desc_(op_desc) {}

AscTensorAttr &AscNodeOutputs::operator[](uint32_t index) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_desc_);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_desc_->MutableOutputDesc(index));
  const auto attr = op_desc_->MutableOutputDesc(index)->GetOrCreateAttrsGroup<AscTensorAttr>();
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(attr);
  attr->dtype.tensor_desc_ = op_desc_->MutableOutputDesc(index).get();
  attr->format.tensor_desc_ = op_desc_->MutableOutputDesc(index).get();
  return *attr;
}

std::vector<AscTensorAttr *> AscNodeOutputs::operator()() {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_desc_);
  std::vector<AscTensorAttr *> tensor_attrs;
  for (size_t index = 0u; index < op_desc_->GetOutputsSize(); index++) {
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_desc_->MutableOutputDesc(index));
    const auto tensor_attr = op_desc_->MutableOutputDesc(index)->GetOrCreateAttrsGroup<AscTensorAttr>();
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(tensor_attr);
    tensor_attr->dtype.tensor_desc_ = op_desc_->MutableOutputDesc(index).get();
    tensor_attr->format.tensor_desc_ = op_desc_->MutableOutputDesc(index).get();
    tensor_attrs.push_back(tensor_attr);
  }
  return tensor_attrs;
}

AscNodeInputs::AscNodeInputs(ge::Node *node) : node_(node) {}

AscTensorAttr &AscNodeInputs::operator[](uint32_t index) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(node_);
  const auto in_anchor = node_->GetInDataAnchor(index);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(in_anchor);
  const auto out_anchor = in_anchor->GetPeerOutAnchor();
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(out_anchor);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(out_anchor->GetOwnerNode());
  const auto op_desc = out_anchor->GetOwnerNode()->GetOpDesc();
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_desc);
  auto outputs = AscNodeOutputs(op_desc);
  return outputs[out_anchor->GetIdx()];
}

uint32_t AscNodeInputs::Size() {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(node_);
  return node_->GetAllInDataAnchorsSize();
}


// 此处op_desc和GetOrCreateAttrsGroup的返回值未判空,内部构造AscNode前已判空
// 资料需注明不允许外部用户构造AscNode
AscNode::AscNode(const OpDescPtr &op_desc, const ComputeGraphPtr &compute_graph) :
  Node(op_desc, compute_graph), inputs(this), outputs(this->GetOpDesc()),
  attr(*(op_desc->GetOrCreateAttrsGroup<AscNodeAttr>())) {}

AscNodeIter::AscNodeIter(ge::ComputeGraph::Vistor<ge::NodePtr>::Iterator &&iter) : impl_(iter) {}

AscNodeIter &AscNodeIter::operator++() {
  impl_++;
  return *this;
}

AscNodePtr AscNodeIter::operator*() {
  auto ptr = *impl_;
  return std::dynamic_pointer_cast<AscNode>(ptr);
}

bool AscNodeIter::operator!=(const AscNodeIter &other) const {
  return impl_ != other.impl_;
}

AscNodeVisitor::AscNodeVisitor(ge::ComputeGraph::Vistor<ge::NodePtr> &&visitor)
    : impl_(visitor) {}

AscNodeIter AscNodeVisitor::begin() {
  return AscNodeIter(impl_.begin());
}

AscNodeIter AscNodeVisitor::end() {
  return AscNodeIter(impl_.end());
}

AscGraphImpl::AscGraphImpl(const char *name) :
  compute_graph_(ComGraphMakeShared<ComputeGraph>(name)) {}

std::string AscGraphImpl::GetName() const {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(compute_graph_);
  return compute_graph_->GetName();
}


void AscGraphImpl::SetTilingKey(const uint32_t tiling_key) {
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  graph_attr_group_ptr->tiling_key = static_cast<int64_t>(tiling_key);
}

int64_t AscGraphImpl::GetTilingKey() const{
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  return graph_attr_group_ptr->tiling_key;
}

void AscGraphImpl::AddNode(ge::Operator &op) {
  const auto op_desc = ge::OpDescUtils::GetOpDescFromOperator(op);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_desc);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(compute_graph_);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_desc->GetOrCreateAttrsGroup<AscNodeAttr>());
  AscNodePtr asc_node(new (std::nothrow) AscNode(op_desc, compute_graph_));
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(asc_node);
  const auto init_ret = asc_node->Init();
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, init_ret == GRAPH_SUCCESS);
  ConstNodePtr const_node = asc_node;
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED,
    ge::NodeUtilsEx::SetNodeToOperator(op, const_node) == GRAPH_SUCCESS);
  (void)compute_graph_->AddNode(asc_node);
}

AscNodePtr AscGraphImpl::FindNode(const char *name) const{
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(compute_graph_);
  auto node = compute_graph_->FindNode(name);
  auto dst_node = std::dynamic_pointer_cast<AscNode>(node);
  return dst_node;
}

AscNodeVisitor AscGraphImpl::GetAllNodes() const{
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(compute_graph_);
  return AscNodeVisitor(compute_graph_->GetAllNodes());
}

AscNodeVisitor AscGraphImpl::GetInputNodes() const{
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(compute_graph_);
  return AscNodeVisitor(compute_graph_->GetInputNodes());
}

AxisPtr AscGraphImpl::CreateAxis(const std::string &name, Axis::Type type,
                                 const ge::expression::ExpressionPtr &size, const std::vector<int64_t> &from,
                                 const int64_t min_value, const int64_t max_value) {
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  std::shared_ptr<Axis> axis(new (std::nothrow) Axis);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(axis);
  axis->type = type;
  axis->name = name;
  axis->size = size;
  axis->from = from;
  axis->align = kDefaultAlignVal;
  axis->allow_oversize_axis = false;
  axis->allow_unaligned_tail = true;
  axis->id = static_cast<int64_t>(graph_attr_group_ptr->axis.size());
  axis->value_range.first = min_value;
  axis->value_range.second = max_value;

  graph_attr_group_ptr->axis.push_back(std::move(axis));

  return graph_attr_group_ptr->axis.back();
}

std::vector<AxisPtr> AscGraphImpl::GetAllAxis() const{
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  return graph_attr_group_ptr->axis;
}

std::vector<OptionalPtr> AscGraphImpl::GetAllOptional() const{
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  return graph_attr_group_ptr->optional;
}

TransInfoRoadOfGraph AscGraphImpl::GetAllAxisTransInfo() const {
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  return graph_attr_group_ptr->trans_info_road;
}

Optional &AscGraphImpl::CreateOptionalAtt(const std::string &name, uint32_t idx, int32_t min_value, int32_t max_value) {
  CHECK_VALID_IDENTIFIER_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, name);
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, min_value <= max_value);
  return CreateOptionalAtt(name, idx, "int32_t", std::to_string(min_value), std::to_string(max_value));
}

Optional &AscGraphImpl::CreateOptionalAtt(const std::string &name, uint32_t idx, uint32_t min_value, uint32_t max_value) {
  CHECK_VALID_IDENTIFIER_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, name);
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, min_value <= max_value);
  return CreateOptionalAtt(name, idx, "uint32_t", std::to_string(min_value) + "U", std::to_string(max_value) + "U");
}

Optional &AscGraphImpl::CreateOptionalAtt(const std::string &name, uint32_t idx, float min_value, float max_value) {
  CHECK_VALID_IDENTIFIER_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, name);
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, min_value <= max_value);
  return CreateOptionalAtt(name, idx, "float", std::to_string(min_value), std::to_string(max_value));
}

Optional &AscGraphImpl::CreateOptionalAtt(const std::string &name, uint32_t idx, int8_t min_value, int8_t max_value) {
  CHECK_VALID_IDENTIFIER_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, name);
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, min_value <= max_value);
  return CreateOptionalAtt(name, idx, "int8_t", std::to_string(min_value), std::to_string(max_value));
}

Optional &AscGraphImpl::CreateOptionalAtt(const std::string &name, uint32_t idx, const std::string &data_type,
                                          const std::string &min_value, const std::string &max_value) {
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  std::shared_ptr<Optional> optional(new (std::nothrow) Optional);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(optional);
  optional->idx = idx;
  optional->name = name;
  optional->data_type = data_type;
  optional->min_value = min_value;
  optional->max_value = max_value;

  graph_attr_group_ptr->optional.push_back(std::move(optional));

  return *(graph_attr_group_ptr->optional.back());
}

Axis *AscGraphImpl::FindAxis(const int64_t axis_id) {
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  if (axis_id < 0 || axis_id > static_cast<int64_t>(graph_attr_group_ptr->axis.size())) {
    return nullptr;
  }
  return graph_attr_group_ptr->axis[axis_id].get();
}

std::pair<AxisPtr, AxisPtr> AscGraphImpl::DoSplit(const int64_t axis_id, const std::string &outer_axis_name,
                                                  const std::string &inner_axis_name, const bool is_tile_split) {
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  const auto &axis = graph_attr_group_ptr->axis;
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, (axis_id >= 0) && (static_cast<size_t>(axis_id) < axis.size()));

  const auto &single_axis = *axis[axis_id];
  const std::string inner_suffix = is_tile_split ? "t" : "b";
  const std::string outer_suffix = is_tile_split ? "T" : "B";
  std::string actual_inner_axis_name = inner_axis_name;
  if (actual_inner_axis_name.empty()) {
    actual_inner_axis_name = single_axis.name + inner_suffix;
  }
  std::string actual_outer_axis_name = outer_axis_name;
  if (actual_outer_axis_name.empty()) {
    actual_outer_axis_name = single_axis.name + outer_suffix;
  }
  const auto inner_size = ge::expression::Expression::CreateExpression(actual_inner_axis_name + "_size");
  const auto outer_size = ge::expression::Ceiling(single_axis.size / inner_size);
  Axis::Type inner_type = is_tile_split ? Axis::AXIS_TYPE_TILE_INNER : Axis::AXIS_TYPE_BLOCK_INNER;
  Axis::Type outer_type = is_tile_split ? Axis::AXIS_TYPE_TILE_OUTER : Axis::AXIS_TYPE_BLOCK_OUTER;
  AxisPtr outer = CreateAxis(actual_outer_axis_name, outer_type, outer_size, {axis_id});
  AxisPtr inner = CreateAxis(actual_inner_axis_name, inner_type, inner_size, {axis_id});
  graph_attr_group_ptr->trans_info_road.push_back({TransType::kSplit, {axis[axis_id]}, {outer, inner}});
  return {outer, inner};
}

std::pair<AxisPtr, AxisPtr> AscGraphImpl::BlockSplit(const int64_t axis_id, const std::string &outer_axis_name,
                                                     const std::string &inner_axis_name) {
  return DoSplit(axis_id, inner_axis_name, outer_axis_name, false);
}

std::pair<AxisPtr, AxisPtr> AscGraphImpl::TileSplit(const int64_t axis_id, const std::string &outer_axis_name,
                                                    const std::string &inner_axis_name) {
  return DoSplit(axis_id, inner_axis_name, outer_axis_name, true);
}

AxisPtr AscGraphImpl::MergeAxis(const std::vector<int64_t> &axis_ids, const std::string &merge_axis_name) {
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  const auto &axis = graph_attr_group_ptr->axis;
  std::string name;
  ge::expression::ExpressionPtr size = ge::expression::Expression::CreateExpression(1);
  std::vector<int64_t> from_axis_ids;
  std::vector<AxisPtr> from_axis;
  for (const auto &axis_id : axis_ids) {
    CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, (axis_id >= 0) && (static_cast<size_t>(axis_id) < axis.size()));
    from_axis.push_back(axis[axis_id]);
    name += axis[axis_id]->name;
    size = size * axis[axis_id]->size;
    from_axis_ids.push_back(axis_id);
  }
  name = merge_axis_name.empty() ? name : merge_axis_name;
  AxisPtr merge_axis = CreateAxis(name, Axis::AXIS_TYPE_MERGED, size, from_axis_ids);
  graph_attr_group_ptr->trans_info_road.push_back({TransType::kMerge, from_axis, {merge_axis}});
  return merge_axis;
}

void AscGraphImpl::DoApplySplit(const AscNodePtr &node, const int64_t outter_id, int64_t inner_id, int64_t original) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(node);
  DoApplySchedAxisSplit(node, outter_id, inner_id, original);
  DoApplyTensorAxisSplit(node, outter_id, inner_id, original);
  return;
}

void AscGraphImpl::DoApplyTensorAxisSplit(const AscNodePtr &node, const int64_t outter_id,
                                          const int64_t inner_id, const int64_t original_id) {
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  const auto &all_axis = graph_attr_group_ptr->axis;
  // check inner_axis before
  const ge::expression::ExpressionPtr &split_size = all_axis[inner_id]->size;
  for (uint32_t i = 0; i < node->GetAllOutDataAnchorsSize(); i++) {
    std::tie(node->outputs[i].axis, node->outputs[i].repeats, node->outputs[i].strides) =
        AxisUtils::SplitView({node->outputs[i].axis, node->outputs[i].repeats, node->outputs[i].strides},
                             split_size,
                             outter_id,
                             inner_id,
                             original_id);
  }
  return;
}

void AscGraphImpl::DoApplySchedAxisSplit(const AscNodePtr &node, const int64_t outter_id,
                                         const int64_t inner_id, const int64_t original_id) {
  std::vector<int64_t> new_node_attr_axis;
  if (node->attr.sched.initial_axis.size() == 0U) {
    node->attr.sched.initial_axis = node->attr.sched.axis;
  }
  const auto &node_axis = node->attr.sched.axis;
  for (auto &node_axis_id : node_axis) {
    if (node_axis_id == original_id) {
      new_node_attr_axis.push_back(outter_id);
      new_node_attr_axis.push_back(inner_id);
    } else {
      new_node_attr_axis.push_back(node_axis_id);
    }
  }
  node->attr.sched.axis = new_node_attr_axis;
  return;
}

void AscGraphImpl::ApplySplit(const AscNodePtr &node, const int64_t outter_id, const int64_t inner_id) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(node);
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  const auto &all_axis = graph_attr_group_ptr->axis;
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED,
    (outter_id >= 0) && (outter_id < static_cast<int64_t>(all_axis.size())) &&
    (inner_id >= 0) && (inner_id < static_cast<int64_t>(all_axis.size())));
  const auto &out_axis = *all_axis[outter_id];
  const auto &in_axis = *all_axis[inner_id];
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, (out_axis.type == Axis::AXIS_TYPE_BLOCK_OUTER &&
    in_axis.type == Axis::AXIS_TYPE_BLOCK_INNER) ||
    (out_axis.type == Axis::AXIS_TYPE_TILE_OUTER && in_axis.type == Axis::AXIS_TYPE_TILE_INNER));
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED,
    (out_axis.from.size() == 1U) && (in_axis.from.size() == 1U) && (out_axis.from[0] == in_axis.from[0]));
  DoApplySplit(node, outter_id, inner_id, out_axis.from[0]);
}

void AscGraphImpl::DoApplyMerge(const AscNodePtr &node, const int64_t merged_axis_id, const std::vector<int64_t> &original) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(node);
  DoApplySchedAxisMerge(node, merged_axis_id, original);
  DoApplyTensorAxisMerge(node, merged_axis_id, original);
}

void AscGraphImpl::DoApplySchedAxisMerge(const AscNodePtr &node, const int64_t merged_axis_id,
                                         const std::vector<int64_t> &original) {
  std::vector<int64_t> new_node_attr_axis;
  auto cur_iter = original.begin();
  if (node->attr.sched.initial_axis.size() == 0U) {
    node->attr.sched.initial_axis = node->attr.sched.axis;
  }
  for (const auto axis_id : node->attr.sched.axis) {
    if (cur_iter != original.end() && axis_id == *cur_iter) {
      cur_iter++;
      if (cur_iter == original.end()) {
        new_node_attr_axis.push_back(merged_axis_id);
      }
    } else {
      new_node_attr_axis.push_back(axis_id);
    }
  }
  ASCIR_ASSERT_TRUE(
      cur_iter == original.begin() || cur_iter == original.end(),
      "node {%s} has sched.axis %s but origin is %s",
      node->GetNamePtr(),
      ViewMemberToString(node->attr.sched.axis).c_str(),
      ViewMemberToString(original).c_str());
  node->attr.sched.axis = new_node_attr_axis;
}


// original中的轴不连续时没法做合轴
// 判断轴是否连续 stride_i == repeat_{i+1} * stride_{i+1}
bool CheckContinuous(const AscNodePtr &node, const uint32_t tensor_index, const std::vector<int64_t> &original) {
  std::vector<ge::expression::ExpressionPtr> repeats;
  std::vector<ge::expression::ExpressionPtr> strides;
  auto cur = original.begin();
  auto axis = node->outputs[tensor_index].axis;
  for (uint32_t axis_index = 0U; axis_index < axis.size(); axis_index++) {
    if (cur != original.end() && axis[axis_index] == *cur) {
      cur++;
      repeats.emplace_back(node->outputs[tensor_index].repeats[axis_index]);
      strides.emplace_back(node->outputs[tensor_index].strides[axis_index]);
    }
  }
  ASCIR_ASSERT_TRUE(
      cur == original.begin() || cur == original.end(),
      "node {%s}'s output[%u] has axis %s but origin is %s",
      node->GetNamePtr(), tensor_index,
      ViewMemberToString(axis).c_str(),
      ViewMemberToString(original).c_str());
  if (repeats.size() <= 1U) {
    return true;
  }
  for (uint32_t i = 0U; i < repeats.size() - 1; i++) {
    if (*(strides[i]) != *(repeats[i + 1] * strides[i + 1])) {
      GELOGD("strides of %u is %s but {repeats * strides} of %u is %s",
             i,
             strides[i]->Str().c_str(),
             i + 1,
             (repeats[i + 1] * strides[i + 1])->Str().c_str());
      return false;
    }
  }
  return true;
}

void AscGraphImpl::DoApplyTensorAxisMerge(const AscNodePtr &node, const int64_t merged_axis_id,
                                          const std::vector<int64_t> &original) {
  for (uint32_t i = 0; i < node->GetAllOutDataAnchorsSize(); i++) {
    if (!CheckContinuous(node, i, original)) {
      GELOGW("%s's [%u]th output's view is not continuous.", node->GetNamePtr(), i);
      continue;
    }
    std::tie(node->outputs[i].axis, node->outputs[i].repeats, node->outputs[i].strides) =
        AxisUtils::MergeView({node->outputs[i].axis, node->outputs[i].repeats, node->outputs[i].strides},
                             merged_axis_id,
                             original);
  }
}

void AscGraphImpl::ApplyMerge(const AscNodePtr &node, const int64_t merged_axis_id) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(node);
  const auto graph_attr_group_ptr = GetOrCreateGraphAttrsGroup();
  const auto &all_axis = graph_attr_group_ptr->axis;
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED,
    (merged_axis_id >= 0) && (merged_axis_id < static_cast<int64_t>(all_axis.size())));
  const auto &axis = *all_axis[merged_axis_id];
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, (axis.type == Axis::AXIS_TYPE_MERGED) &&
    axis.from.size() >= kMinMergeAxisFromSize);
  DoApplyMerge(node, merged_axis_id, axis.from);
}

void AscGraphImpl::ApplyReorder(const AscNodePtr &node, const std::vector<int64_t> &reordered_axis) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(node);
  const auto &node_axis = node->attr.sched.axis;
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, node_axis.size() == reordered_axis.size());

  for (const auto axis_id : reordered_axis) {
    const auto it = std::find(node_axis.begin(), node_axis.end(), axis_id);
    CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, it != node_axis.end());
  }
  node->attr.sched.axis = reordered_axis;
  for (const auto output_ptr : node->outputs()) {
    auto &output = *output_ptr;
    std::vector<int64_t> new_axis;
    std::vector<ge::expression::ExpressionPtr> new_repeat;
    std::vector<ge::expression::ExpressionPtr> new_strides;
    auto output_axis = output.axis;
    for (const auto axis_id : reordered_axis) {
      const auto it = std::find(output_axis.begin(), output_axis.end(), axis_id);
      if (it == output_axis.end()) {
        continue;
      }
      const auto pos = std::distance(output_axis.begin(), it);
      new_axis.push_back(output_axis[pos]);
      new_repeat.push_back(output.repeats[pos]);
      new_strides.push_back(output.strides[pos]);
    }
    output.axis = new_axis;
    output.repeats = new_repeat;
    output.strides = new_strides;
  }
}

AscGraphAttr *AscGraphImpl::GetOrCreateGraphAttrsGroup() {
  return const_cast<AscGraphAttr *>(static_cast<const AscGraphImpl *>(this)->GetOrCreateGraphAttrsGroup());
}

const AscGraphAttr *AscGraphImpl::GetOrCreateGraphAttrsGroup() const {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(compute_graph_);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(compute_graph_->GetOrCreateAttrsGroup<AscGraphAttr>());
  return compute_graph_->GetOrCreateAttrsGroup<AscGraphAttr>();
}

AscOpOutput AscGraphImpl::CreateContiguousData(const char *name,
                                               const ge::DataType &dt,
                                               const vector<ge::Axis> &axes,
                                               const vector<std::vector<int64_t>> &axis_continuous_map,
                                               const Format &format) {
  ASCIR_ASSERT_EQ(axes.size(), axis_continuous_map.size());
  auto data_op_desc = OpDescBuilder(name, kAscData).AddOutput("y").Build();
  ASCIR_ASSERT_NOTNULL(data_op_desc);
  auto data_op = std::make_shared<Operator>(OpDescUtils::CreateOperatorFromOpDesc(data_op_desc));
  ASCIR_ASSERT_NOTNULL(data_op);
  auto data_attr = data_op_desc->GetOrCreateAttrsGroup<AscDataNodeAttr>();
  ASCIR_ASSERT_NOTNULL(data_attr);
  AddNode(*data_op);
  data_op_desc->SetExtAttr(ascir::cg::RELATED_OP, data_op);
  data_attr->axis_continuous_map = axis_continuous_map;
  data_attr->format = format; // node上的format
  data_attr->sched.exec_order = ascir::cg::CodeGenUtils::GenNextExecId(*data_op);
  data_attr->index = data_attr->sched.exec_order;

  AscOpOutput asc_op_output(data_op.get(), 0U); // data只有一个输出
  asc_op_output.dtype = dt;
  asc_op_output.format = format; // tensor上的format
  asc_op_output.SetContiguousView(axes);
  *asc_op_output.vectorized_axis = AxisUtils::GetDefaultVectorizedAxis(*asc_op_output.axis, -1);
  return asc_op_output;
}

AscOpOutput AscGraphImpl::CreateContiguousOut(const char *name,
                                              const DataType &dt,
                                              const vector<ge::Axis> &axes,
                                              const Format &format) {
  auto out_op_desc = OpDescBuilder(name, kAscOutput).AddInput("x").AddOutput("y").Build();
  ASCIR_ASSERT_NOTNULL(out_op_desc);
  auto out_op = std::make_shared<Operator>(OpDescUtils::CreateOperatorFromOpDesc(out_op_desc));
  ASCIR_ASSERT_NOTNULL(out_op);
  AddNode(*out_op);
  out_op_desc->SetExtAttr(ascir::cg::RELATED_OP, out_op);
  AscOpOutput asc_op_output(out_op.get(), 0U); // output只有一个输出
  asc_op_output.dtype = dt;
  asc_op_output.format = format;
  asc_op_output.SetContiguousView(axes);
  *asc_op_output.vectorized_axis = AxisUtils::GetDefaultVectorizedAxis(*asc_op_output.axis, -1);
  return asc_op_output;
}

AscGraph::AscGraph(const char *name) :
  impl_(std::shared_ptr<AscGraphImpl>(new (std::nothrow) AscGraphImpl(name))) {}

std::string AscGraph::GetName() const {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->GetName();
}

void AscGraph::SetTilingKey(const uint32_t tiling_key) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  impl_->SetTilingKey(tiling_key);
}

int64_t AscGraph::GetTilingKey() const{
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->GetTilingKey();
}

Axis &AscGraph::CreateAxis(const std::string &name, const ge::expression::ExpressionPtr &size,
                           const int64_t min_value, const int64_t max_value) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return *(impl_->CreateAxis(name, Axis::AXIS_TYPE_ORIGINAL, size, {}, min_value, max_value));
}

Optional &AscGraph::CreateOptionalAtt(const std::string &name, uint32_t idx, int32_t min_value, int32_t max_value) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->CreateOptionalAtt(name, idx, min_value, max_value);
}
Optional &AscGraph::CreateOptionalAtt(const std::string &name, uint32_t idx, uint32_t min_value, uint32_t max_value) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->CreateOptionalAtt(name, idx, min_value, max_value);
}
Optional &AscGraph::CreateOptionalAtt(const std::string &name, uint32_t idx, float min_value, float max_value) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->CreateOptionalAtt(name, idx, min_value, max_value);
}
Optional &AscGraph::CreateOptionalAtt(const std::string &name, uint32_t idx, int8_t min_value, int8_t max_value) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->CreateOptionalAtt(name, idx, min_value, max_value);
}
Optional &AscGraph::CreateOptionalAtt(const std::string &name, uint32_t idx, const std::string &data_type,
                                      const std::string &min_value, const std::string &max_value) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->CreateOptionalAtt(name, idx, data_type, min_value, max_value);
}

Axis *AscGraph::FindAxis(const int64_t axis_id) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->FindAxis(axis_id);
}

void AscGraph::AddNode(ge::Operator &op) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  impl_->AddNode(op);
}

AscNodePtr AscGraph::FindNode(const char *name) const {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->FindNode(name);
}

AscNode &AscGraph::Node(const char *name) const {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  auto node_ptr = impl_->FindNode(name);
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(node_ptr);
  return *node_ptr;
}

AscNodeVisitor AscGraph::GetAllNodes() const {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->GetAllNodes();
}

AscNodeVisitor AscGraph::GetInputNodes() const {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->GetInputNodes();
}

std::pair<AxisPtr, AxisPtr> AscGraph::BlockSplit(const int64_t axis_id, const std::string &inner_axis_name,
                                                 const std::string &outer_axis_name) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  CHECK_VALID_IDENTIFIER_ALLOW_EMPTY_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, inner_axis_name);
  CHECK_VALID_IDENTIFIER_ALLOW_EMPTY_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, outer_axis_name);
  return impl_->BlockSplit(axis_id, inner_axis_name, outer_axis_name);
}

std::pair<AxisPtr, AxisPtr> AscGraph::TileSplit(const int64_t axis_id, const std::string &inner_axis_name,
                                                const std::string &outer_axis_name) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->TileSplit(axis_id, inner_axis_name, outer_axis_name);
}

AxisPtr AscGraph::MergeAxis(const std::vector<int64_t> &axis_ids, const std::string &merge_axis_name) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->MergeAxis(axis_ids, merge_axis_name);
}

void AscGraph::ApplySplit(const AscNodePtr &node, const int64_t outter_id, const int64_t inner_id) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  impl_->ApplySplit(node, outter_id, inner_id);
}

void AscGraph::ApplyMerge(const AscNodePtr &node, const int64_t merged_axis_id) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  impl_->ApplyMerge(node, merged_axis_id);
}

void AscGraph::ApplyReorder(const AscNodePtr &node, const std::vector<int64_t> &reordered_axis) {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  impl_->ApplyReorder(node, reordered_axis);
}

std::vector<AxisPtr> AscGraph::GetAllAxis() const{
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->GetAllAxis();
}

std::vector<OptionalPtr> AscGraph::GetAllOptional() const{
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(impl_);
  return impl_->GetAllOptional();
}
AscGraph::~AscGraph() {
  for (const auto &node: impl_->GetAllNodes()) {
    const auto &op_desc = node->GetOpDesc();
    if (op_desc != nullptr) {
      // 打破shared ptr的循环引用
      op_desc->DelExtAttr(ascir::cg::RELATED_OP);
    }
  }
}

bool AscGraph::CheckExprValid() const {
  int32_t axis_index = -1;
  for (const auto &axis : GetAllAxis()) {
    axis_index++;
    CHECK_FALSE_RETURN_FALSE(axis != nullptr, "Axis ptr is null, index[%d].", axis_index)
    CHECK_FALSE_RETURN_FALSE(axis->size != nullptr,
      "Axis size is null, index[%d].", axis_index)
  }
  int32_t node_index = -1;
  for (const auto &node : GetAllNodes()) {
    node_index++;
    CHECK_FALSE_RETURN_FALSE(node != nullptr, "Node ptr is null, index[%d].", node_index)
    int32_t output_index = -1;
    for (const auto &tensor : node->outputs()) {
      output_index++;
      CHECK_FALSE_RETURN_FALSE(tensor != nullptr,
        "Tensor ptr is null, index[%d], node name[%s].", output_index, node->GetName().c_str())
      int32_t repeat_index = -1;
      for (const auto &repeat : tensor->repeats) {
        repeat_index++;
        CHECK_FALSE_RETURN_FALSE(repeat != nullptr,
          "Tensor repeat ptr is null, index[%d], node name[%s], tensor index[%d].",
          repeat_index, node->GetName().c_str(), output_index)
      }
      int32_t stride_index = -1;
      for (const auto &stride : tensor->strides) {
        stride_index++;
        CHECK_FALSE_RETURN_FALSE(stride != nullptr,
          "Tensor stride ptr is null, index[%d], node name[%s], tensor index[%d].",
          stride_index, node->GetName().c_str(), output_index)
      }
      int32_t vec_stride_index = -1;
      for (const auto &vectorized_stride : tensor->vectorized_strides) {
        vec_stride_index++;
        CHECK_FALSE_RETURN_FALSE(vectorized_stride != nullptr,
          "Tensor vectorized_stride ptr is null, index[%d], node name[%s], tensor index[%d].",
          vec_stride_index, node->GetName().c_str(), output_index)
      }
    }
  }
  return true;
}

bool AscGraph::CheckAxisValid() const {
  int64_t id_index = 0;
  const auto axes = GetAllAxis();
  for (const auto &axis : axes) {
    CHECK_FALSE_RETURN_FALSE(axis, "Axis ptr is null, index[%ld].", id_index)
    CHECK_FALSE_RETURN_FALSE(axis->id == id_index,
      "Axis index[%ld] is not equal to id[%ld].", id_index, axis->id)
    id_index++;
  }
  int32_t node_index = -1;
  for (const auto &node : GetAllNodes()) {
    node_index++;
    CHECK_FALSE_RETURN_FALSE(node != nullptr,
      "Node ptr is null, index[%d].", node_index)
    std::set<int64_t> sched_axis_set;
    int32_t sched_axis_index = -1;
    for (const auto &sched_axis : node->attr.sched.axis) {
      sched_axis_index++;
      CHECK_FALSE_RETURN_FALSE(sched_axis >= 0,
        "Invalid sched axis[%ld], node_name[%s], index[%d].",
        sched_axis, node->GetName().c_str(), sched_axis_index)
      CHECK_FALSE_RETURN_FALSE(sched_axis < static_cast<int64_t>(axes.size()),
        "Invalid sched axis[%ld], node_name[%s], index[%d].",
        sched_axis, node->GetName().c_str(), sched_axis_index)
      const auto iter = sched_axis_set.find(sched_axis);
      CHECK_FALSE_RETURN_FALSE(iter == sched_axis_set.end(),
        "Redundant sched axis[%ld], node_name[%s].",
        sched_axis, node->GetName().c_str())
      sched_axis_set.insert(sched_axis);
    }
    int32_t output_index = -1;
    for (const auto &tensor : node->outputs()) {
      output_index++;
      CHECK_FALSE_RETURN_FALSE(tensor != nullptr,
        "Tensor ptr is null, index[%d], node name[%s].", output_index, node->GetName().c_str())
      CHECK_FALSE_RETURN_FALSE(tensor->axis.size() == tensor->repeats.size(),
        "Tensor axis size[%lu] is not equal to repeat size[%lu], , index[%d], node name[%s].",
        static_cast<uint64_t>(tensor->axis.size()), static_cast<uint64_t>(tensor->repeats.size()),
        output_index, node->GetName().c_str())
      CHECK_FALSE_RETURN_FALSE(tensor->axis.size() == tensor->strides.size(),
        "Tensor axis size[%lu] is not equal to stride size[%lu], , index[%d], node name[%s].",
        static_cast<uint64_t>(tensor->axis.size()), static_cast<uint64_t>(tensor->strides.size()),
        output_index, node->GetName().c_str())
      for (const auto &axis : tensor->axis) {
        CHECK_FALSE_RETURN_FALSE(axis >= 0,
          "Invalid tensor axis[%ld].", axis)
        CHECK_FALSE_RETURN_FALSE(axis < static_cast<int64_t>(axes.size()),
          "Invalid tensor axis[%ld].", axis)
      }
      for (const auto &vectorized_axis : tensor->vectorized_axis) {
        CHECK_FALSE_RETURN_FALSE(vectorized_axis >= 0,
          "Invalid tensor vectorized_axis[%ld].", vectorized_axis)
        CHECK_FALSE_RETURN_FALSE(vectorized_axis < static_cast<int64_t>(axes.size()),
          "Invalid tensor vectorized_axis[%ld].", vectorized_axis)
      }
    }
  }
  return true;
}

bool AscGraph::CheckExecOrderValid() const {
  std::set<int64_t> exec_order_set;
  for (const auto &node : GetAllNodes()) {
    const auto exec_order = node->attr.sched.exec_order;
    const auto iter = exec_order_set.find(exec_order);
    CHECK_FALSE_RETURN_FALSE(iter == exec_order_set.end(),
      "Redundant exec_order[%ld].", exec_order)
    exec_order_set.insert(exec_order);
  }
  return true;
}

bool AscGraph::CheckTensorValid() const {
  for (const auto &node : GetAllNodes()) {
    int32_t output_index = -1;
    for (const auto &tensor : node->outputs()) {
      output_index++;
      if (tensor->mem.alloc_type == AllocType::ALLOC_TYPE_GLOBAL) {
        continue;
      }
      if ((tensor->buf.id != kIdNone) && (tensor->que.id == kIdNone)) {
        continue;
      }
      if ((tensor->buf.id == kIdNone) && (tensor->que.id != kIdNone)) {
        CHECK_FALSE_RETURN_FALSE(tensor->que.depth > 0,
          "Invalid que depth[%ld], tensor index[%d], node[%s].",
          tensor->que.depth, output_index, node->GetName().c_str())
        CHECK_FALSE_RETURN_FALSE(tensor->que.buf_num > 0,
          "Invalid que buf_num[%ld], tensor index[%d], node[%s].",
          tensor->que.buf_num, output_index, node->GetName().c_str())
        continue;
      }
      GE_LOGE("Invalid mem, alloc type[%d], que id[%ld], buf id[%ld], tensor index[%d], node[%s].",
              static_cast<int32_t>(tensor->mem.alloc_type), tensor->que.id, tensor->buf.id,
              output_index, node->GetName().c_str());
      return false;
    }
  }
  return true;
}

bool AscGraph::CheckNodeConnectionValid() const {
  for (const auto &node : GetAllNodes()) {
    for (uint32_t index = 0U; index < node->inputs.Size(); index++) {
      CHECK_FALSE_RETURN_FALSE(node->GetInDataAnchor(index) != nullptr,
        "Input is not connected, index[%u], node[%s].",
        index, node->GetName().c_str())
      CHECK_FALSE_RETURN_FALSE(node->GetInDataAnchor(index)->GetPeerOutAnchor() != nullptr,
        "Input is not connected, index[%u], node[%s].",
        index, node->GetName().c_str())
    }
  }
  return true;
}

bool AscGraph::CheckValid() const {
  if (!CheckExprValid()) {
    return false;
  }
  if (!CheckAxisValid()) {
    return false;
  }
  if (!CheckExecOrderValid()) {
    return false;
  }
  if (!CheckTensorValid()) {
    return false;
  }
  if (!CheckNodeConnectionValid()) {
    return false;
  }
  return true;
}

TransInfoRoadOfGraph AscGraph::GetAllAxisTransInfo() const {
  ASCIR_ASSERT_NOTNULL(impl_);
  return impl_->GetAllAxisTransInfo();
}

AscOpOutput AscGraph::CreateContiguousData(const char *name,
                                           const ge::DataType &dt,
                                           const vector<ge::Axis> &axes,
                                           const vector<std::vector<int64_t>> &axis_continuous_map,
                                           const Format &format) {
  ASCIR_ASSERT_NOTNULL(impl_);
  return impl_->CreateContiguousData(name, dt, axes, axis_continuous_map, format);
}

AscOpOutput AscGraph::CreateContiguousData(const char *name,
                                           const ge::DataType &dt,
                                           const std::vector<ge::Axis> &axes,
                                           const ge::Format &format) {
  return CreateContiguousData(name, dt, axes, kOneAxisContinuousInfo, format);
}

AscOpOutput AscGraph::CreateContiguousOut(const char *name,
                                          const ge::DataType &dt,
                                          const std::vector<ge::Axis> &axes,
                                          const ge::Format &format) {
  ASCIR_ASSERT_NOTNULL(impl_);
  return impl_->CreateContiguousOut(name, dt, axes, format);
}

void AddEdgeForNode(ge::Operator &src_op, int32_t src_index, ge::Operator &dst_op, int32_t dst_index) {
  auto src_node = ge::NodeUtilsEx::GetNodeFromOperator(src_op);
  auto dst_node = ge::NodeUtilsEx::GetNodeFromOperator(dst_op);
  ASCIR_ASSERT_NOTNULL(src_node);
  if (dst_node == nullptr) {
    auto com_graph = src_node->GetOwnerComputeGraph();
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(com_graph);
    auto dst_op_desc = ge::OpDescUtils::GetOpDescFromOperator(dst_op);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(dst_op_desc);
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(dst_op_desc->GetOrCreateAttrsGroup<AscNodeAttr>());
    AscNodePtr dst_asc_node(new (std::nothrow) AscNode(dst_op_desc, com_graph));
    CHECK_NOTNULL_WITH_THROW_EXCEPTION(dst_asc_node);
    (void)dst_asc_node->Init();
    ConstNodePtr const_dst_node = dst_asc_node;
    CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED,
      ge::NodeUtilsEx::SetNodeToOperator(dst_op, const_dst_node) == GRAPH_SUCCESS);
    dst_node = com_graph->AddNode(dst_asc_node);
  }
  const auto ret = ge::GraphUtils::AddEdge(src_node->GetOutDataAnchor(src_index), dst_node->GetInDataAnchor(dst_index));
  CHECK_BOOL_WITH_THROW_EXCEPTION(ge::GRAPH_FAILED, ret == GRAPH_SUCCESS);
}

int64_t AscOpOutput::GenContainerId() {
  CHECK_NOTNULL_WITH_THROW_EXCEPTION(op_);
  return ascir::cg::CodeGenUtils::GenNextContainerId(*op_);
}

void AscOpOutput::UseTQue(const Position pos, const int64_t depth, const int64_t buf_num, const int64_t id) {
  CHECK_BOOL_WITH_THROW_EXCEPTION(PARAM_INVALID, !HasBindToContainer(),
                                  " this tensor has been bound to a que, can not use any other que.");
  CHECK_BOOL_WITH_THROW_EXCEPTION(PARAM_INVALID, buf_num > 0, "input buf_num should greater than 0.");
  CHECK_BOOL_WITH_THROW_EXCEPTION(PARAM_INVALID, depth > 0, "input depth should greater than 0.");
  mem->position = pos;
  mem->alloc_type = AllocType::ALLOC_TYPE_QUEUE;
  buf->id = kIdNone;
  que->depth = depth;
  que->buf_num = buf_num;
  if (id == kIdNone) {
    que->id = GenContainerId();
  } else {
    que->id = id;
  }
}

void AscOpOutput::UseTBuf(const Position pos, const int64_t id) {
  CHECK_BOOL_WITH_THROW_EXCEPTION(PARAM_INVALID, !HasBindToContainer(),
                                  " this tensor has been bound to a buf, can not use any other buf.");
  mem->position = pos;
  mem->alloc_type = AllocType::ALLOC_TYPE_BUFFER;
  que->id = kIdNone;
  if (id == kIdNone) {
    buf->id = GenContainerId();
  } else {
    buf->id = id;
  }
}

bool AscOpOutput::HasBindToContainer() const {
  bool has_bind_que = (que->id != kIdNone);
  bool has_bind_buf = (buf->id != kIdNone);
  // 1.if alloc type has set to que or buffer means has binding to a container
  // 2.if que/buf is valid, means also means has binding to a container
  return ((mem->alloc_type == AllocType::ALLOC_TYPE_QUEUE) || (mem->alloc_type == AllocType::ALLOC_TYPE_BUFFER)) &&
      (has_bind_que || has_bind_buf);
}
}  // namespace ge
